package com.bestv.search.management.command;

import com.bestv.search.common.cache.SystemCache;
import com.bestv.search.common.dataSource.DataSourceKey;
import com.bestv.search.common.model.*;
import com.bestv.search.common.model.uid.UID;
import com.bestv.search.common.service.BizTypeManager;
import com.bestv.search.common.service.InfoManager;
import com.bestv.search.common.service.KeySubjectManager;
import com.bestv.search.common.util.DateUtil;
import com.bestv.search.management.xfire.ISearchWS;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.xfire.client.XFireProxyFactory;
import org.codehaus.xfire.service.Service;
import org.codehaus.xfire.service.binding.ObjectServiceFactory;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.util.StringUtils;

import java.net.MalformedURLException;
import java.text.ParseException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class KeySubjectCommand implements IKeySubjectCommand {

    protected final Log log = LogFactory.getLog(getClass());
    private InfoManager infoManager;
    private KeySubjectManager keySubjectManager;
    private BizTypeManager bizTypeManager;
    private SystemCache systemCache;

    public BizTypeManager getBizTypeManager() {
        return bizTypeManager;
    }

    public void setBizTypeManager(BizTypeManager bizTypeManager) {
        this.bizTypeManager = bizTypeManager;
    }

    public KeySubjectManager getKeySubjectManager() {
        return keySubjectManager;
    }

    public void setKeySubjectManager(KeySubjectManager keySubjectManager) {
        this.keySubjectManager = keySubjectManager;
    }

    public InfoManager getInfoManager() {
        return infoManager;
    }

    public void setInfoManager(InfoManager infoManager) {
        this.infoManager = infoManager;
    }

    @Override
    public String findPType(SysUser user, Map<String, String[]> map, DataSourceKey dsKey) throws JSONException {
        List<String> p_types;

        p_types = infoManager.findPTypes(dsKey);

        JSONArray jsonArray = new JSONArray();
        int i = 1;
        for (String pt : p_types) {
            JSONObject jo = new JSONObject();
            jo.put("name", pt);
            jo.put("code", i++);
            jsonArray.put(jo);
        }
        return "{'p_types':" + jsonArray.toString() + "}";
    }

    @Override
    public String find(SysUser user, Map<String, String[]> map, DataSourceKey dsKey) throws JSONException {
        String[] start = map.get("start");
        String[] limit = map.get("limit");

        int stat, lmt;
        if ("".equals(start[0]))
            stat = -1;
        else
            stat = Integer.parseInt(start[0]);
        if ("".equals(limit))
            lmt = -1;
        else
            lmt = Integer.parseInt(limit[0]);
        int count = keySubjectManager.getKeySubjectCount(dsKey);
        List<KeySubject> kslist = keySubjectManager.getKeySubjects(dsKey, stat, lmt);
        JSONArray array = new JSONArray();
        for (KeySubject ks : kslist) {
            JSONObject jo = new JSONObject();
            jo.put("id", String.valueOf(ks.getId()));
            jo.put("name", ks.getName());
            jo.put("must", ks.getMust());
            jo.put("keywords", ks.getKeywords());
            jo.put("p_type", ks.getP_type());
            array.put(jo);
        }
        return "{'totalCount':" + count + ",'keysubjects':" + array.toString() + "}";
    }

    @Override
    public String get(SysUser user, Map<String, String[]> map, DataSourceKey dsKey) {
        String result = "";
        String[] id = map.get("id");

        if ("".equals(id[0]))
            return "[error]";
        KeySubject ks = keySubjectManager.getById(dsKey, new Long(id[0]));

        try {
            JSONObject jo = keySubjectToJSONObject(ks);
            result = jo.toString();
        } catch (JSONException e) {
            log.error(e);
        }
        return result;
    }

    @Override
    public String save(SysUser user, Map<String, String[]> map, DataSourceKey dsKey) throws ParseException {
        String[] id = map.get("id");
        String[] name = map.get("subjectName");
        // String[] ptypeid = map.get("ptypeid");
        String[] ptype = map.get("ptype");
        String[] keywords = map.get("keywords");
        String[] must = map.get("must");
        String[] validDate = map.get("validDate");
        String[] invalidDate = map.get("invalidDate");

        if ("".equals(name[0]))
            return "{'result':'failure','message':'nameNull'}";
        if ("".equals(ptype[0]))
            return "{'result':'failure','message':'typeNull'}";
        if ("".equals(keywords[0]))
            return "{'result':'failure','message':'keywordsNull'}";
        if ("".equals(validDate[0]))
            return "{'result':'failure','message':'dateNull'}";
        // 存在性判断
        KeySubject existsSubject = keySubjectManager.getByTypeName(dsKey, ptype[0], name[0]);
        if (existsSubject != null) {
            if (!"".equals(id[0])) {
                if (existsSubject.getId() != new Long(id[0]))
                    return "[existed]";
            } else
                return "[existed]";
        }
        // save操作
        KeySubject ks;
        if ("".equals(id[0])) {
            ks = new KeySubject();
            ks.setUpdateFlag(0);// new
            ks.setSite(user.getSite());
            ks.setId(new Long(UID.getUID(ks)));
        } else {
            ks = existsSubject == null ? keySubjectManager.getById(dsKey, new Long(id[0])) : existsSubject;
            ks.setUpdateFlag(1);
        }
        ks.setUpdateTimeForIndex(new Date());
        ks.setCreator(user);
        BizType bt = new BizType(ptype[0]);
        bt = bizTypeManager.saveBizTypes(dsKey, bt);
        ks.setP_type(ptype[0]);
        ks.setName(name[0]);
        ks.setKeywords(keywords[0].replaceAll("/", " "));
        ks.setMust(must[0].replaceAll("/", " "));
        ks.setValidTime(DateUtil.convertStringToDate("yyyy-MM-dd HH:mm", validDate[0]));
        ks.setInvalidTime(DateUtil.convertStringToDate("yyyy-MM-dd HH:mm", invalidDate[0]));
        keySubjectManager.saveKeySubject(dsKey, ks, bt);
        return "{'result':'success','message':''}";
    }

    /**
     * @param user system user
     * @param map  (keys keyValues spacing by blank),contains keywords which need
     *             count frequent
     * @return each single keyword with frequent
     * @throws JSONException json parsing exception
     */
    @Override
    public String findKeyFrequent(SysUser user, Map<String, String[]> map, DataSourceKey dsKey) throws JSONException {
        String[] key = map.get("keys");
        if ("".equals(key[0]))
            return "";
        log.debug(key[0].trim());
        String[] keys = key[0].trim().split("[ ]+");

        Map<String, Integer> keywords = keySubjectManager.findKeyFrequent(dsKey, keys);
        Set<String> keySet = keywords.keySet();
        JSONArray array = new JSONArray();
        for (String k : keySet) {
            JSONObject jo = new JSONObject();
            jo.put("keyword", k);
            jo.put("num", keywords.get(k));
            array.put(jo);
        }
        return "{'keywords':" + array.toString() + "}";
    }

    @Override
    public String delete(SysUser user, Map<String, String[]> map, DataSourceKey dsKey) {
        String[] id = map.get("id");

        if ("".equals(id[0]))
            return "[error]";

        keySubjectManager.deleteKeySubjectById(dsKey, new Long(id[0]));

        return "{'result':'success','message':''}";
    }

    /**
     * Call Web Service Function. Search programs from Search Engine
     *
     * @param user
     * @param map  ,contain search condition parameters(p_type(the results are
     *             all in the p_type),keys(spacing by blank),start,limit)
     * @return
     * @throws JSONException
     */
    @Override
    public String searchResultByKeysInPtype(SysUser user, Map<String, String[]> map, DataSourceKey dsKey)
            throws JSONException {
        String[] ptype = map.get("ptype");
        String[] key = map.get("keys");
        String[] stat = map.get("start");
        String[] slimit = map.get("limit");
        String[] musts = map.get("must");
        String must = musts == null ? "" : musts[0];

        if ("".equals(ptype[0]))
            return "[error]";
        if ("".equals(key))
            return "[error]";
        Service serviceModel = new ObjectServiceFactory().create(ISearchWS.class);
        String url = systemCache.getWebServiceEngineUrls().get(dsKey.toString());
        String[] soapUrls = StringUtils.tokenizeToStringArray(url, SystemCache.WEB_SERVICE_EURL_DELIMITERS);

        if (soapUrls == null || soapUrls.length == 0) {
            log.error("Gets info failed, no web service interface found from site " + dsKey.toString());
            return "{'totalCount':0,'results':[error]}";
        }

        ISearchWS service = null;
        try {
            service = (ISearchWS) new XFireProxyFactory().create(serviceModel, soapUrls[0]);
        } catch (MalformedURLException e) {
            log.error(e);
        }
        String remoteRt = service.searchInType(ptype[0], key[0], must, new Integer(stat[0]), new Integer(slimit[0]));
        log.debug(remoteRt);
        if (remoteRt.matches("^\\([\\d, ]+\\)&\\d+")) {
            log.debug("remoteRt match the RegExp");
            String[] semiRts = remoteRt.split("&");
            if (semiRts.length != 2)
                return "Result from Enigne error!";

            Set<Info> infos = infoManager.getInfoSetByIds(dsKey, semiRts[0]);
            if (infos == null)
                return "{\"totalCount\":0,\"results\":[]}";
            JSONArray array = new JSONArray();
            for (Info info : infos) {
                JSONObject jo = infoToJSONObjectForKeyStat(info);
                array.put(jo);
            }
            return "{\"totalCount\":\"" + Long.parseLong(semiRts[1]) + "\",\"results\":" + array.toString() + "}";
        }
        if ("noDoc".equals(remoteRt))
            return "{\"totalCount\":0,\"results\":[]}";
        return remoteRt;
    }

    /**
     * Search programs from Search Engine
     *
     * @param user
     * @param map  ,contain search condition parameters(p_type(the results are
     *             all NOT in the p_type),keys(spacing by blank),start,limit)
     * @return
     * @throws JSONException
     */
    @Override
    public String searchResultByKeysOutPtype(SysUser user, Map<String, String[]> map, DataSourceKey dsKey)
            throws JSONException {
        String[] ptype = map.get("ptype");
        String[] key = map.get("keys");
        String[] stat = map.get("start");
        String[] slimit = map.get("limit");
        String[] musts = map.get("must");
        String must = musts == null ? "" : musts[0];

        if ("".equals(ptype[0]))
            return "[error]";
        if ("".equals(key))
            return "[error]";
        Service serviceModel = new ObjectServiceFactory().create(ISearchWS.class);
        String url = systemCache.getWebServiceEngineUrls().get(dsKey.toString());
        String[] soapUrls = StringUtils.tokenizeToStringArray(url, SystemCache.WEB_SERVICE_EURL_DELIMITERS);

        if (soapUrls == null || soapUrls.length == 0) {
            log.error("Gets info failed, no web service interface found from site " + dsKey.toString());
            return "{'totalCount':0,'results':[error]}";
        }

        ISearchWS service = null;
        try {
            service = (ISearchWS) new XFireProxyFactory().create(serviceModel, soapUrls[0]);
        } catch (MalformedURLException e) {
            log.error(e);
        }
        String remoteRt = service.searchOutType(ptype[0], key[0], must, new Integer(stat[0]), new Integer(slimit[0]));
        log.debug(remoteRt);
        if (remoteRt.matches("^\\([\\d, ]+\\)&\\d+")) {
            log.debug("remoteRt match the RegExp");
            String[] semiRts = remoteRt.split("&");
            if (semiRts.length != 2)
                return "Result from Enigne error!";

            Set<Info> infos = infoManager.getInfoSetByIds(dsKey, semiRts[0]);
            if (infos == null)
                return "{\"totalCount\":0,\"results\":[]}";
            JSONArray array = new JSONArray();
            for (Info info : infos) {
                JSONObject jo = infoToJSONObjectForKeyStat(info);
                array.put(jo);
            }
            return "{\"totalCount\":\"" + Long.parseLong(semiRts[1]) + "\",\"results\":" + array.toString() + "}";
        }
        if ("noDoc".equals(remoteRt))
            return "{\"totalCount\":0,\"results\":[]}";
        return remoteRt;
    }

    /**
     * find program number and key number for each p_type
     *
     * @param user
     * @param map
     * @return
     * @throws JSONException
     */
    @Override
    public String findProAndKeyNumInPTypes(SysUser user, Map<String, String[]> map, DataSourceKey dsKey)
            throws JSONException {
        Map<String, Integer[]> rt = infoManager.findProAndKeyNumInPTypes(dsKey);
        int knum = infoManager.getDistinctCountOfKeysInPtype(dsKey, "all");
        Set<String> ptypes = rt.keySet();
        JSONArray array = new JSONArray();
        int p_sum = 0;// ,k_sum = 0;
        int i = 0;
        for (String ptype : ptypes) {
            JSONObject jo = new JSONObject();
            Integer[] nums = rt.get(ptype);
            jo.put("p_type", ptype);
            jo.put("p_num", nums[0]);
            jo.put("k_num", nums[1]);
            array.put(++i, jo);
            p_sum += nums[0];
            // knum += nums[1];
            // k_sum += nums[1];
        }
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("p_type", "totalCount");
        jsonObject.put("p_num", p_sum);
        jsonObject.put("k_num", knum);
        array.put(0, jsonObject);
        return "{'results':" + array.toString() + "}";
    }

    /**
     * find program number and key number for each p_type
     *
     * @param user
     * @param map
     * @return
     * @throws JSONException
     */
    @Override
    public String findProAndTagNumInPTypes(SysUser user, Map<String, String[]> map, DataSourceKey dsKey)
            throws JSONException {
        Map<String, Integer[]> rt = infoManager.findProAndTagNumInPTypes(dsKey);
        int tnum = infoManager.getDistinctCountOfTagsInPtype(dsKey, "all");
        Set<String> ptypes = rt.keySet();
        JSONArray array = new JSONArray();
        int p_sum = 0, i = 0;// ,k_sum = 0;
        for (String ptype : ptypes) {
            JSONObject jo = new JSONObject();
            Integer[] nums = rt.get(ptype);
            jo.put("p_type", ptype);
            jo.put("p_num", nums[0]);
            jo.put("k_num", nums[1]);
            array.put(++i, jo);
            p_sum += nums[0];
            // k_sum += nums[1];
        }
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("p_type", "totalCount");
        jsonObject.put("p_num", p_sum);
        jsonObject.put("k_num", tnum);
        array.put(0, jsonObject);
        return "{'results':" + array.toString() + "}";
    }

    /**
     * Find each keyword and its frequent in p_type, paging
     *
     * @param user
     * @param map
     * @return
     * @throws JSONException
     */
    @Override
    public String findEachKeyAndNumInPType(SysUser user, Map<String, String[]> map, DataSourceKey dsKey)
            throws JSONException {
        String[] start = map.get("start");
        String[] limit = map.get("limit");
        String[] ptype = map.get("ptype");
        String[] totalCount = map.get("count");

        String[][] rt = infoManager.findEachKeyAndNumInPType(dsKey, ptype[0], Integer.parseInt(start[0]),
                Integer.parseInt(limit[0]));
        JSONArray array = new JSONArray();
        for (int i = 0; i < rt[0].length; ++i) {
            JSONObject jo = new JSONObject();
            jo.put("keyword", rt[0][i]);
            jo.put("num", rt[1][i]);
            array.put(jo);
        }
        return "{\"totalCount\":\"" + Integer.parseInt(totalCount[0]) + "\",\"results\":" + array.toString() + "}";
    }

    /**
     * Find each tag and its frequent in p_type, paging
     *
     * @param user
     * @param map
     * @return
     * @throws JSONException
     */
    @Override
    public String findEachTagAndNumInPType(SysUser user, Map<String, String[]> map, DataSourceKey dsKey)
            throws JSONException {
        String[] start = map.get("start");
        String[] limit = map.get("limit");
        String[] ptype = map.get("ptype");
        String[] totalCount = map.get("count");

        String[][] rt = infoManager.findEachTagAndNumInPtype(dsKey, ptype[0], Integer.parseInt(start[0]),
                Integer.parseInt(limit[0]));
        JSONArray array = new JSONArray();
        for (int i = 0; i < rt[0].length; ++i) {
            JSONObject jo = new JSONObject();
            jo.put("tag", rt[0][i]);
            jo.put("num", rt[1][i]);
            array.put(jo);
        }
        return "{\"totalCount\":\"" + Integer.parseInt(totalCount[0]) + "\",\"results\":" + array.toString() + "}";
    }

    /**
     * @throws JSONException
     */
    @Override
    public String findCrossKeyword(SysUser user, Map<String, String[]> map, DataSourceKey dsKey) throws JSONException {

        log.debug(dsKey);
        List<Integer> list = infoManager.findCrossKeyword(dsKey);

        JSONArray array = new JSONArray();
        for (Integer i : list) {
            JSONObject jo = new JSONObject();
            jo.put("num", i);
            array.put(jo);
        }
        return "{\"results\":" + array.toString() + "}";
    }

    @Override
    public String findCrossKeywordDetail(SysUser user, Map<String, String[]> map, DataSourceKey dsKey)
            throws JSONException {
        String[] start = map.get("start");
        String[] limit = map.get("limit");
        String[] ptype1 = map.get("ptype1");
        String[] ptype2 = map.get("ptype2");

        log.debug(dsKey);
        List<String> list = infoManager.findCrossKeywordDetail(dsKey, ptype1[0], ptype2[0], Integer.parseInt(start[0]),
                Integer.parseInt(limit[0]));
        int count = infoManager.fingCrossKeyCount(dsKey, ptype1[0], ptype2[0]);

        JSONArray array = new JSONArray();
        for (String s : list) {
            JSONObject jo = new JSONObject();
            jo.put("key", s);
            array.put(jo);
        }
        return "{\"totalCount\":\"" + count + "\",\"results\":" + array.toString() + "}";
    }

    public JSONObject keySubjectToJSONObject(KeySubject ks) throws JSONException {
        JSONObject jo = new JSONObject();
        jo.put("id", ks.getId());
        jo.put("keywords", ks.getKeywords());
        jo.put("name", ks.getName());
        jo.put("must", ks.getMust());
        jo.put("ptype", String.valueOf(ks.getBizType().getId()));
        jo.put("time",
                ks.getValidTime() == null ? "" : DateUtil.convertDateToString("yyyy-MM-dd HH:mm", ks.getValidTime()));
        jo.put("vtime",
                ks.getValidTime() == null ? "" : DateUtil.convertDateToString("yyyy-MM-dd HH:mm", ks.getInvalidTime()));
        return jo;
    }

    private JSONObject infoToJSONObjectForKeyStat(Info info) throws JSONException {
        JSONObject jo = new JSONObject();
        jo.put("id", String.valueOf(info.getId()));
        jo.put("name", info.getName());
        jo.put("p_type", info.getP_type());
        jo.put("updateTime", DateUtil.convertDateToString("yyyy-MM-dd HH:mm", info.getUpdateTime()));
        Set<Keyword> keySet = info.getKeywords();
        StringBuffer sb = new StringBuffer();
        int i = 0;
        for (Keyword key : keySet) {
            sb.append(key.getKeyword());
            if (++i < keySet.size())
                sb.append(",");
        }
        jo.put("keywords", sb.toString());
        Set<Tag> tagSet = info.getTags();
        StringBuffer tagBf = new StringBuffer();
        i = 0;
        for (Tag t : tagSet) {
            tagBf.append(t.getTag());
            if (++i < tagSet.size())
                tagBf.append(",");
        }
        jo.put("tags", tagBf.toString());
        jo.put("description", info.getDescription());
        if (info instanceof Entrance)
            jo.put("type", info.getType() == null ? "" : info.getType().getName());
        else if (info instanceof Program) {
            Program p = (Program) info;
            jo.put("type", info.getType() == null ? "" : info.getType().getName());
            jo.put("actors", p.getActors() == null ? "" : p.getActors());
            jo.put("directors", p.getDirectors() == null ? "" : p.getDirectors());
        } else if (info instanceof Series) {
            Series p = (Series) info;
            jo.put("type", info.getType() == null ? "" : info.getType().getName());
            jo.put("actors", p.getActors() == null ? "" : p.getActors());
            jo.put("directors", p.getDirectors() == null ? "" : p.getDirectors());
        } else if (info instanceof Schedule) {
            Schedule p = (Schedule) info;
            jo.put("actors", p.getActors() == null ? "" : p.getActors());
            jo.put("directors", p.getDirectors() == null ? "" : p.getDirectors());
            if (p.getEndPlayTime().before(new Date()))
                jo.put("type", "回看");
            else
                jo.put("type", "预告");
        }
        return jo;
    }

    public SystemCache getSystemCache() {
        return systemCache;
    }

    public void setSystemCache(SystemCache systemCache) {
        this.systemCache = systemCache;
    }
}
